/*
 * Matthew Cramer, Jesse Martinez, Marc Mendoza 
 * CSE 325 Lab 5
 * File: TestingInterface.c
 * Description: Manager that handles calls to the Queue Manager, LRU, and Memory Manager
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "../QueueManager/QueueManager.h"
#include "../MemoryManager/MemoryManager.h"
#include "../LRU/LRU.h"
#define MAX_PT_SIZE 1024 
#define MAX_USER_PT 12
#define MAX_SYS_PT 4
#define MAX_PT 16


void list(int);

int  main(int argc, char *argv[])
{
	char command[500];
	char argument[3] [30];
	char *temp;
	int exit = 1, check=0, manualInput = 1, initiate=0;
	int i=0;//total managers
	FILE *file;
	
    //Open File for Use
	if(argc == 2)
	{
		file = fopen(argv[1], "r");
		manualInput =0;
	}
	
	while(exit != 0)
	{
        printf(": ");
        
        //For terminal use
		if(manualInput == 1)
		{
			scanf("%[^\n]",command);
			getchar();
		}
		
        //For input file use
		else if(manualInput == 0)
		{

            if (fgets(command, sizeof command, file)) 
            {
                char* p = strchr(command,'\n');
                if (p)
                    *p = '\0';
                printf("%s\n", command);
            }
		}
		
		//uses a string tokenizer to split files based on whitespace
		temp = strtok(command, " ");
		
		strcpy(command, temp);
		
        //Command to display help for list of commands and use
        if(strcmp(command, "help") == 0)
        {
            //Display Menu

            printf("\nMemory Manager Commands: \n");
            printf("init mem\n");
            printf("list {user | system | pagetable [page_table_id]}\n");
            printf("alloc_pt page_table_size\n");
            printf("dealloc_pt page_table_id\n");
            printf("page_fault page_table_id page_num\n");
            printf("LRU - Clears Memory and loads 1 page table of size 1024 and calls page fault on each page\n");
            printf("help\n");
            printf("EXIT\n\n");

        }
        //If command is init memory
		else if(strcmp(command, "init") == 0)
		{
			int k=0;
			temp = strtok(NULL, " ");
			//puts all managers into array
            
            //Check to see if correct number of arguments
			while(temp != NULL)
			{
				strcpy(argument[k], temp);
				temp = strtok(NULL, " ");
				k++;
			}

            //If correct number of arguments, allocate queues
			if(k == 1)
			{
                //Init Physical Mem and Backing Store
                if(strcmp(argument[0], "mem") == 0)
                {
                    clearMemory();
                    initiate=1;
                }
                else
                {
                    printf("ERROR: INCORRECT ARGUMENT\n");
                }
			}
            else
            {
				printf("ERROR: INCORRECT ARGUMENTS\n");
			}
		}
        //If Command is List
		else if(strcmp(command, "list") == 0 && initiate==1)
		{
			temp = strtok(NULL, " ");
            int k=0;
            //Check to see if arguments are correct
            while(temp != NULL)
			{
				strcpy(argument[k], temp);
				temp = strtok(NULL, " ");
				k++;
			}
            //If queue requested, check to see if manager is being used
			if(k > 0)
			{
				if(strcmp(argument[0], "user") == 0 && k == 1)
                {
                   
                    list(-2);
                }
                else if (strcmp(argument[0], "system") == 0 && k == 1)
                {
                    list(-3);
                }
                else if (strcmp(argument[0], "pagetable") == 0 && k == 2)
                {
                    if(atoi(argument[1]) >= 0)
                    {
                        list(atoi(argument[1]));
                    }
                    else
                        printf("ERROR: INVALID ID\n");
                }
                else
                {
                    printf("ERROR: INCORRECT ARGUMENT(S)\n");
                }
			}
            //List all managers being used
			else if(k==0)
			{
                list(-1);
			}
            else
              printf("ERROR: INCORRECT ARGUMENTS\n");  
		}
        //If command is alloc_pt
		else if(strcmp(command, "alloc_pt") == 0 && initiate==1)
		{
			temp = strtok(NULL, " ");
            int k=0;
            //Check to see if correct number of arguments
            while(temp != NULL)
			{
				strcpy(argument[k], temp);
				temp = strtok(NULL, " ");
				k++;
			}
			if(k == 1)
			{
				int size = atoi(argument[0]);
                if(size > MAX_PT_SIZE || size < 1)
                {
                    printf("ERROR: PAGE TABLE SIZE MUST BE LESS THAN %d AND GREATER THAN 0\n",MAX_PT_SIZE);
                }
                else
                {
                    printf("User(1) or System(2)? ");
                    
                    //For terminal use
                    if(manualInput == 1)
                    {
                        scanf("%[^\n]",command);
                        getchar();
                    }
                    
                    //For input file use
                    else if(manualInput == 0)
                    {
                        
                        if(fgets(command, sizeof command, file)) 
                        {
                            char* p = strchr(command,'\n');
                            if (p)
                                *p = '\0';
                            printf("%s\n", command);
                        }
                    }
                    
                    //uses a string tokenizer to split files based on whitespace
                    temp = strtok(command, " ");
                    
                    strcpy(command, temp);
                    int check=-1,type=0;
                    if(strcmp(command, "User") == 0 || strcmp(command, "user") == 0 || strcmp(command, "1") == 0)
                    {
                        check = alloc_pt(size,1);
                        type=1;
                    }
                    else if(strcmp(command, "System") == 0 || strcmp(command, "system") == 0 || strcmp(command, "2") == 0)
                    {
                        check = alloc_pt(size,2);
                        type=2;
                    }
                    else
                    {
                        printf("ERROR: OWNER NOT RECOGNIZED\n");
                    }
                    
                    if(check>=0)
                    {
                        printf("Page Table created with ID: %d\n",check);
                    }
                    else
                    {
                        if(type==1)
                            printf("ERROR: MAX PROCESSES FOR USER ALREADY\n");
                        else if(type==2)
                            printf("ERROR: MAX PROCESSES FOR SYSTEM ALREADY\n");
                    }
                }
			}
            else
                printf("ERROR: INCORRECT ARGUMENTS\n");
		}
        //If command is dealloc
		else if(strcmp(command, "dealloc_pt") == 0 && initiate==1)
		{
			int k = 0;
			temp = strtok(NULL, " ");
            //Check to see if correct number of arguments
			while(temp != NULL)
			{
				strcpy(argument[k], temp);
				temp = strtok(NULL, " ");
				k++;
			}
            //If not correct arguments
			if(k == 1)
			{
				int id = atoi(argument[0]);
                int check = dealloc_pt(id);
                if(check == 1)
                    printf("Page Table Found! Deallocated page table and data with ID: %d\n",id);
                else
                    printf("ERROR: PAGE TABLE NOT FOUND\n");
			}
			else
			{
                printf("ERROR: INCORRECT ARGUMENTS\n");
			}
		}
        //If commnad is Retrieve
		else if(strcmp(command, "page_fault") == 0 && initiate==1)

		{
			temp = strtok(NULL," ");
            int k=0;
            //Check to see if correct number of arguments
            while(temp != NULL)
			{
				strcpy(argument[k], temp);
				temp = strtok(NULL, " ");
				k++;
			}
			if(k== 2)
			{
                int id = atoi(argument[0]);
                int page = atoi(argument[1]);
                int check = page_fault(id,page);
                if(check == -1)
                    printf("ERROR: MEMORY CAPACITY ERROR\n");
                else if(check == -2)
                    printf("ERROR: FRAME TYPE ERROR\n");
                else if(check == -3)
                    printf("ERROR: VALID BIT INCONSISTANCY\n");
                else if(check == -4)
                    printf("ERROR: VALID BIT INCORRECT\n");
                else if(check == -5)
                    printf("ERROR: PAGE NOT IN PAGE TABLE LIMIT\n");
                else if(check == -6)
                    printf("ERROR: PAGE TABLE ID NOT FOUND\n");
                
			}
            else
            {
                printf("ERROR: INCORRECT ARGUMENTS\n");
            }
		}
        //Exit program command
        else if(strcmp(command, "LRU") == 0)
        {
            initiate=1;
            clearMemory();
            alloc_pt(1024,1);
            int i;
            for(i=0; i<1024; i++)
            {
                page_fault(0,i);
            }
        }
		else if(strcmp(command, "EXIT") == 0 || strcmp(command, "exit") == 0)
		{
            exit = 0;
		}
        //If init_IPC has not been called initially, error
        else if(initiate==0)
        {
            printf("ERROR: PLEASE INITIATE MEMORY\n");
        }
        //If command not recognized, error
		else
		{
			printf("ERROR: COMMAND NOT RECOGNIZED\n");
		}
	}
	return 0;
}


//Lists the messages in a queue
void list(int select)
{
    memory_block *mem = getLogicalMemory();
    memory_block *bs = getBackingStore();
    //Get User Data
    if(select == -2 || select == -1)
    {
        int i,index;
        printf("User Data:\n");
        //Search each page table to see if it is for User
        for(i=0; i<MAX_PT; i++)
        {

            index=mem[0].pagetable[i].frame;

            //If page table valid
            if(index > 0 && mem[index].owner == 1)
            {
                int size = mem[index].ptsize;
                int j;
                printf("ID: %d\n",mem[index].ID);
                //Itterate through page table
                for(j=0; j<size; j++)
                {
                    int page = mem[index].pagetable[j].frame;
                    //If it is in Physical Memory
                    if(mem[index].pagetable[j].frameType == 1)
                        printf("Page: %d Location: Physical Memory at address: %d Data: %d\n",j,page,mem[page].data);
                    //if it is in Backing Store
                    else if(mem[index].pagetable[j].frameType == 2)
                        printf("Page: %d Location: Backing Store at address: %d Data: %d\n",j,page,bs[page].data);
                    else if(mem[index].pagetable[j].frameType == -1)
                        printf("Page: %d Location: NOT YET PAGE FAULTED\n",j);
                    else
                        printf("ERROR: PAGE NOT FOUND\n");                
                }
            }
        }
    }
    //Get System Data
    if(select == -3 || select == -1)
    {
        int i,index;
        printf("System Data:\n");
        //Search each page table to see if it is for System
        for(i=0; i<MAX_PT; i++)
        {
            index=mem[0].pagetable[i].frame;
            //If page table valid
            if(index > 0 && mem[index].owner == 2)
            {
                int size = mem[index].ptsize;
                int j;
                printf("ID: %d\n",mem[index].ID);
                //Itterate through page table
                for(j=0; j<size; j++)
                {
                    int page = mem[index].pagetable[j].frame;
                    //If it is in Physical Memory
                    if(mem[index].pagetable[j].frameType == 1)
                        printf("Page: %d Location: Physical Memory at address: %d Data: %d\n",j,page,mem[page].data);
                    //if it is in Backing Store
                    else if(mem[index].pagetable[j].frameType == 2)
                        printf("Page: %d Location: Backing Store at address: %d Data: %d\n",j,page,bs[page].data);
                    else if(mem[index].pagetable[j].frameType == -1)
                        printf("Page: %d Location: NOT YET PAGE FAULTED\n",j);
                    else
                        printf("ERROR: PAGE NOT FOUND\n");
                }
            }
        }
    }
    //Get Page Table(s)
    if(select >= 0 || select == -1)
    {
        //Get all Page Tables and Print
        if(select == -1)
        {
            printf("Page Tables: \n");
            int i,index;
            //Itterate through all page tables
            for(i=0; i<MAX_PT; i++)
            {
                index=mem[0].pagetable[i].frame;
                //If page table valid
                if(index > 0)
                {
                    int size = mem[index].ptsize;
                    int j;
                    if(mem[index].owner == 1)
                        printf("User - ");
                    else
                        printf("System - ");
                    printf("ID: %d\n",mem[index].ID);
                    //Display each page
                    for(j=0; j<size; j++)
                    {
                        int page = mem[index].pagetable[j].frame;
                        //If it is in Physical Memory
                        if(mem[index].pagetable[j].frameType == 1)
                            printf("Page: %d Location: Physical Memory at address: %d\n",j,page);
                        //if it is in Backing Store
                        else if(mem[index].pagetable[j].frameType == 2)
                            printf("Page: %d Location: Backing Store at address: %d\n",j,page);
                        else if(mem[index].pagetable[j].frameType == -1)
                            printf("Page: %d Location: NOT YET PAGE FAULTED\n",j);
                        else
                            printf("ERROR: PAGE NOT FOUND\n");
                    }
                }
            }
        }
        //Get Requested Page Table
        else
        {
            int i=0,index,temp=0,ID;
            //Scan through each page table to see if it is the one searching for
            while(i<MAX_PT && temp !=1)
            {
                index=mem[0].pagetable[i].frame;
                ID = mem[index].ID;
                //If page table is the correct one, print it
                if(ID == select)
                {
                    int size = mem[index].ptsize;
                    int j;
                    if(mem[index].owner == 1)
                        printf("User - ");
                    else
                        printf("System - ");
                    printf("ID: %d\n",mem[index].ID);
                    //Print pages in page table found
                    for(j=0; j<size; j++)
                    {
                        int page = mem[index].pagetable[j].frame;
                        //If it is in Physical Memory
                        if(mem[index].pagetable[j].frameType == 1)
                            printf("Page: %d Location: Physical Memory at address: %d\n",j,page);
                        //if it is in Backing Store
                        else if(mem[index].pagetable[j].frameType == 2)
                            printf("Page: %d Location: Backing Store at address: %d\n",j,page);
                        else if(mem[index].pagetable[j].frameType == -1)
                            printf("Page: %d Location: NOT YET PAGE FAULTED\n",j);
                        else
                            printf("ERROR: PAGE NOT FOUND\n");
                    }
                    temp=1;
                }
                //go to next page table
                i++;
            }
            //Page table was not found with the given ID
            if(temp==0)
            {
                printf("ERROR: ID NOT FOUND\n");
            }
        }
        
    }
	
}
